package tech.bmatch.redpack.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import tech.bmatch.common.util.DistanceUtil;
import tech.bmatch.common.util.IDUtil;
import tech.bmatch.redpack.model.CouponType;
import tech.bmatch.redpack.model.Merchant;
import tech.bmatch.redpack.model.MoneyOffRedPack;
import tech.bmatch.redpack.model.MyRedPack;
import tech.bmatch.redpack.model.MySharedRedPack;
import tech.bmatch.redpack.model.RedPack;
import tech.bmatch.redpack.model.RedPackCondition;
import tech.bmatch.redpack.model.RedPackType;
import tech.bmatch.redpack.model.SharedRedPack;
import tech.bmatch.redpack.param.CreateRedPackParam;
import tech.bmatch.redpack.service.RedPackService;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;


/**
 * 红包服务的实现类
 *
 * @author: Awake
 * @date: 2018-11-02 17:26
 **/
@Component
public class RedPackServiceImpl implements RedPackService {

    /**
     * logger
     */
    public static final Logger logger = LoggerFactory.getLogger(RedPackServiceImpl.class);
    /**
     * 文件映射
     */
    private static ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 红包存储
     */
    private static File file = new File("./RedPacks.json");
    /**
     * 红包的缓存
     */
    private static List<RedPack> caches;
    /**
     * 商家缓存
     */
    private static Map<String, Merchant> merchantCache = new HashMap<>();
    /**
     * 我领取的红包缓存
     */
    private static Map<String, List<MyRedPack>> myRedPackCache = new HashMap<>();
    /**
     * 主分享红包缓存
     */
    private static Map<String, SharedRedPack> sharedRedPackCache = new HashMap<>();
    /**
     * 主分享红包下的被分享红包缓存
     */
    private static Map<String, List<MySharedRedPack>> myShareRedPackCache = new HashMap<>();
    /**
     * 当前经纬度
     */
    private static double lon = 0;
    private static double lat = 0;

    /**
     * 初始化数据
     */
    static {
        try {
            caches = objectMapper.readValue(file, new TypeReference<List<RedPack>>() {
            });
        } catch (IOException e) {
            logger.error("读取文件错误", e);
        }

        merchantCache.put("test001", new Merchant("test001", "肯德基",
                "http://p1.meituan.net/waimaipoi/b19e9d2f6a71fbbe3574d59fad59cc3315082.jpeg.webp", 1, 2));
        merchantCache.put("test002", new Merchant("test002", "麦当劳",
                "http://p0.meituan.net/0.84.63/xianfu/aa86bc1b9a218ea5e094b861c03b59b94873.jpg.webp", 3, 4));
        merchantCache.put("test003", new Merchant("test003", "必胜客",
                "http://p0.meituan.net/waimaipoi/1bd7d1f47a6b5697c716d19b682c440416509.jpg.webp", 1, 1));
    }


    /**
     * 创建红包
     *
     * @param createRedPackParam
     * @return
     */
    @Override
    public RedPack create(CreateRedPackParam createRedPackParam) {
        RedPack redPack = null;

        if (createRedPackParam.getCouponType().equals(CouponType.MONEYOFF)) {
            MoneyOffRedPack moneyOffRedPack = new MoneyOffRedPack();
            initRedPack(createRedPackParam, moneyOffRedPack);
            moneyOffRedPack.setTotalAmount(createRedPackParam.getTotalAmount() * 100);
            moneyOffRedPack.setMerchantId(createRedPackParam.getMerchantId());
            Merchant merchant = merchantCache.get(moneyOffRedPack.getMerchantId());
            moneyOffRedPack.setMerchantName(merchant.getName());
            moneyOffRedPack.setMerchantLogo(merchant.getLogo());

            redPack = moneyOffRedPack;
        } else {
            redPack = new RedPack();
            initRedPack(createRedPackParam, redPack);
        }

        caches.add(redPack);
        store();
        return redPack;
    }

    /**
     * 查询红包
     *
     * @param redPackType
     * @return
     */
    @Override
    public List<RedPack> query(RedPackType redPackType) {
        List<RedPack> list = caches.stream().filter(redPack -> redPack.getType().equals(redPackType))
                .collect(Collectors.toList());
        // list.stream().filter(redPack -> redPack.getCouponType().equals(CouponType.MONEYOFF)).forEach(redPack -> {
        //     MoneyOffRedPack moneyOffRedPack = (MoneyOffRedPack) redPack;
        // });
        return list;
    }

    /**
     * 天降红包服务
     *
     * @param userId 用户ID
     * @return 获得红包的实例
     */
    @Override
    public List<MyRedPack> rainPack(String userId) {
        if (userId == null) {
            return null;
        }
        //取出
        List<MyRedPack> myRedPackList = myRedPackCache.get(userId);
        if (myRedPackList == null) {
            myRedPackList = new ArrayList<>();
            myRedPackCache.put(userId, myRedPackList);
        }

        long redPackCount = myRedPackList.stream()
                .filter(myRedPack -> DateUtils.isSameDay(new Date(), myRedPack.getGmtCreated())).count();

        //如果已经领取了红包
        if (redPackCount > 0) {
            return null;
        }

        List<RedPack> redPackList = query(RedPackType.VOUCHER);
        Map<String, MoneyOffRedPack> moneyOffRedPackMap = new HashMap<>();
        Iterator<RedPack> it1 = redPackList.iterator();
        while (it1.hasNext()) {
            MoneyOffRedPack moneyOffRedPack = (MoneyOffRedPack) it1.next();
            moneyOffRedPackMap.put(moneyOffRedPack.getMerchantId(), moneyOffRedPack);
        }

        // 进行排序，按照商家位置先后
        List<Merchant> merchantOfDistance = new ArrayList<>();
        Collection<Merchant> values = merchantCache.values();
        Iterator<Merchant> it2 = values.iterator();
        while (it2.hasNext()) {
            Merchant merchant = it2.next();
            merchant.setDistance(DistanceUtil.getDistance(merchant.getLon(), merchant.getLat(), lon, lat));
            merchantOfDistance.add(merchant);
        }

        Collections.sort(merchantOfDistance, (o1, o2) -> {
            double d = o1.getDistance() - o2.getDistance();
            return (int) d;
        });

        List<RedPack> redpacksOfDistance = new ArrayList<>();
        for (Merchant merchant : merchantOfDistance) {
            MoneyOffRedPack moneyOffRedPack = moneyOffRedPackMap.get(merchant.getId());
            if (moneyOffRedPack != null) {
                redpacksOfDistance.add(moneyOffRedPack);
            }
            if (redpacksOfDistance.size() > 3)
                break;
        }

        Calendar cal = Calendar.getInstance();

        List<MyRedPack> result = new ArrayList<>();
        redpacksOfDistance.stream().forEach(redPack -> {
            MyRedPack myRedPack = new MyRedPack();
            myRedPack.setId(IDUtil.getId());
            myRedPack.setGmtCreated(new Date());
            myRedPack.setGmtModified(new Date());
            myRedPack.setUserId(userId);
            myRedPack.setRedPack(redPack);

            cal.add(Calendar.DAY_OF_MONTH, redPack.getValidity());
            myRedPack.setValidityDay(cal.getTime());
            //清空时间
            cal.clear();
            result.add(myRedPack);
        });

        //回填
        myRedPackList.addAll(result);

        return result;
    }


    /**
     * 抢红包的主分享红包创建
     *
     * @param sharedRedPack 初始参数
     * @return 主分享红包
     */
    @Override
    public SharedRedPack createSharedPack(SharedRedPack sharedRedPack) {

        if (sharedRedPack == null) {
            return null;
        }
        // if (sharedRedPack.getSharedUserId()==null || sharedRedPack.getSharedUserId().equals("")){
        //     return null;
        // }

        if (StringUtils.isEmpty(sharedRedPack.getSharedUserId())) {
            logger.error("The sharedRedPack userId is null.");
            return null;
        }
        if (sharedRedPack.getMaxAmount() == 0) {
            logger.error("The sharedRedPack need maxAmount.");
            return null;
        }
        if (sharedRedPack.getMaxIndex() == 0) {
            logger.error("The sharedRedPack need maxIndex.");
            return null;
        }

        Date date = new Date();
        sharedRedPack.setId(IDUtil.getId());
        sharedRedPack.setGmtCreated(date);
        sharedRedPack.setGmtModified(date);
        sharedRedPack.setMaxAmount(sharedRedPack.getMaxAmount() * 100);
        sharedRedPackCache.put(sharedRedPack.getId(), sharedRedPack);
        return sharedRedPack;
    }

    /**
     * 抢红包
     *
     * @param sharedRedPackId 主分享红包ID
     * @param userId          用户ID
     * @return
     */
    @Override
    public List<MySharedRedPack> grabPack(String sharedRedPackId, String userId) {

        //得到当前主分享红包下的所有红包
        List<MySharedRedPack> mySharedRedPacks = myShareRedPackCache.get(sharedRedPackId);
        //防止数据为null
        if (mySharedRedPacks == null) {
            mySharedRedPacks = new ArrayList<>();
            myShareRedPackCache.put(sharedRedPackId, mySharedRedPacks);
        }
        //判断当前用户有没有领取红包
        boolean hasMySharedRedPack = mySharedRedPacks.stream()
                .filter(pack -> pack.getMyRedPack().getUserId().equals(userId)).findFirst().isPresent();
        if (hasMySharedRedPack) {
            return mySharedRedPacks;
        }
        //创建我的被分享红包实例并添加入缓存
        createMySharedRedPack(sharedRedPackId, userId, mySharedRedPacks);
        return mySharedRedPacks;
    }


    /**
     * 初始化红包
     *
     * @param createRedPackParam
     * @param redPack
     */
    private void initRedPack(CreateRedPackParam createRedPackParam, RedPack redPack) {
        redPack.setId(IDUtil.getId());
        redPack.setGmtCreated(new Date());
        redPack.setGmtModified(new Date());
        redPack.setCouponType(createRedPackParam.getCouponType());
        redPack.setType(createRedPackParam.getRedPackType());
        redPack.setValidity(createRedPackParam.getValidity());
        redPack.setAmount(createRedPackParam.getAmount() * 100);

        List<RedPackCondition> conditions = new ArrayList<>();
        redPack.setConditions(conditions);
        createRedPackParam.getConditionIds().forEach(id -> {
            RedPackCondition condition = new RedPackCondition();
            condition.setId(id);
            conditions.add(condition);
        });
    }


    /**
     * 创建我的被分享红包实例并添加到缓存
     *
     * @param sharedRedPackId  主分享红包ID
     * @param userId           用户ID
     * @param mySharedRedPacks 主分享红包下的所有红包
     */
    private void createMySharedRedPack(String sharedRedPackId, String userId, List<MySharedRedPack> mySharedRedPacks) {
        MySharedRedPack mySharedRedPack = new MySharedRedPack();
        //得到主分享红包
        SharedRedPack sharedRedPack = sharedRedPackCache.get(sharedRedPackId);
        //初始化参数
        mySharedRedPack.setSharedRedPack(sharedRedPack);
        mySharedRedPack.setId(IDUtil.getId());
        mySharedRedPack.setGmtCreated(new Date());
        mySharedRedPack.setGmtModified(new Date());
        mySharedRedPack.setIndex(mySharedRedPacks.size() + 1);
        //初始化我的红包实例
        MyRedPack myRedPack = createMyRedPack(userId, mySharedRedPack, sharedRedPack);
        mySharedRedPack.setMyRedPack(myRedPack);
        mySharedRedPacks.add(mySharedRedPack);
    }

    /**
     * 获得我的红包实例
     *
     * @param userId          用户ID
     * @param mySharedRedPack 我的被分享红包
     * @param sharedRedPack   主分享红包
     * @return
     */
    private MyRedPack createMyRedPack(String userId, MySharedRedPack mySharedRedPack, SharedRedPack sharedRedPack) {

        //核心红包实例
        RedPack redPack = new RedPack();
        redPack.setType(RedPackType.CASH);
        redPack.setCouponType(CouponType.CASH);
        redPack.setId(IDUtil.getId());
        redPack.setGmtCreated(new Date());
        redPack.setGmtModified(new Date());
        //限制三天
        redPack.setValidity(3);

        //判断是否最大红包
        if (mySharedRedPack.getIndex() == sharedRedPack.getMaxIndex()) {
            redPack.setAmount(sharedRedPack.getMaxAmount());
        } else {
            int maxAmount = sharedRedPack.getMaxAmount();
            Random ra =new Random();
            redPack.setAmount(ra.nextInt(maxAmount)+100);
        }

        MyRedPack myRedPack = new MyRedPack();
        myRedPack.setId(IDUtil.getId());
        myRedPack.setGmtCreated(new Date());
        myRedPack.setGmtModified(new Date());
        myRedPack.setUserId(userId);
        myRedPack.setRedPack(redPack);
        //有效期
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_MONTH, redPack.getValidity());
        myRedPack.setValidityDay(cal.getTime());

        //Java8语法 省去操作
        myRedPackCache.compute(userId, (key, value) -> {
            if (value == null) {
                value = new ArrayList<>();
            }
            value.add(myRedPack);
            return value;
        });
        return myRedPack;
    }

    /**
     * 文件保存
     */
    public static void store() {
        if (caches == null) {
            return;
        }
        try {
            objectMapper.writeValue(file, caches);
        } catch (IOException e) {
            logger.error("存储文件错误", e);
        }
    }
}

